// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.core.codegen.config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;
import org.dengues.commons.ui.swt.colorstyledtext.EModeLanguage;
import org.dengues.core.components.EJETCodePart;
import org.dengues.core.components.IComponentFilesNaming;
import org.dengues.core.components.IComponentsFactory;
import org.dengues.core.components.IXMLComponent;
import org.dengues.core.prefs.IDenguesPrefsConstant;
import org.dengues.designer.core.DesignerCorePlugin;
import org.dengues.designer.core.components.ComponentFilesNaming;
import org.dengues.designer.core.components.ComponentsFactory;
import org.dengues.designer.core.i18n.Messages;
import org.dengues.ui.DenguesUiPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.codegen.jet.JETEmitter;
import org.eclipse.emf.common.util.BasicMonitor;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class JETCodeGeneratorEmittersPoolFactory {

    public static int PREC = 0;

    private static boolean initInProgress = false;

    private static HashMap<JETTemplateBean, JETEmitter> emitterPool = null;

    private static Logger log = Logger.getLogger(JETCodeGeneratorEmittersPoolFactory.class);

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initializeNotJob".
     */
    public static void initializeNotJob() {
        if (!initInProgress) {
            try {
                initInProgress = true;
                long start = System.currentTimeMillis();
                PREC = 1;
                final IComponentsFactory compFactory = new ComponentsFactory();
                compFactory.init();
                CodeGenJETTemplatesFactory.getInstance().init();
                final List<JETTemplateUtil> templates = CodeGenJETTemplatesFactory.getInstance().getTemplates();
                final List<IXMLComponent> components = compFactory.getComponents();
                List<JETTemplateBean> jetBeans = new ArrayList<JETTemplateBean>();
                for (JETTemplateUtil template : templates) {
                    JETTemplateBean jetBean = initializeUtilTemplate(template, EModeLanguage.JAVA);
                    jetBeans.add(jetBean);
                }

                if (components != null) {
                    for (IXMLComponent component : components) {
                        for (EJETCodePart part : component.getAvailableCodeParts()) {
                            initComponent(EModeLanguage.JAVA, jetBeans, part, component);
                            // PREC++;
                        }
                    }
                }
                initializeEmittersPool(jetBeans, EModeLanguage.JAVA, null);
                log.info("Initialize " + components.size() + " Templates in " //$NON-NLS-1$ //$NON-NLS-2$
                        + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$
            } finally {
                initInProgress = false;
            }
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initialize".
     */
    public static void initialize() {
        if (!initInProgress) {
            Job job = new Job(Messages.getString("CodeGeneratorEmittersPoolFactory.JobLabel", "...")) { //$NON-NLS-1$

                @Override
                protected IStatus run(IProgressMonitor monitor) {
                    try {
                        initInProgress = true;
                        final IComponentsFactory compFactory = new ComponentsFactory();
                        compFactory.init();
                        CodeGenJETTemplatesFactory.getInstance().init();
                        final List<JETTemplateUtil> templates = CodeGenJETTemplatesFactory.getInstance().getTemplates();
                        final List<IXMLComponent> components = compFactory.getComponents();
                        monitor.beginTask(
                                Messages.getString("CodeGeneratorEmittersPoolFactory.Task.Label"), 2 * templates.size() + 4 //$NON-NLS-1$
                                        * components.size());
                        List<JETTemplateBean> jetBeans = new ArrayList<JETTemplateBean>();
                        long start = System.currentTimeMillis();
                        for (JETTemplateUtil template : templates) {
                            JETTemplateBean jetBean = initializeUtilTemplate(template, EModeLanguage.JAVA);
                            jetBeans.add(jetBean);
                            monitor.worked(1);
                        }
                        if (components != null) {
                            for (IXMLComponent component : components) {
                                for (EJETCodePart part : component.getAvailableCodeParts()) {
                                    initComponent(EModeLanguage.JAVA, jetBeans, part, component);
                                }
                                monitor.worked(1);
                            }
                        }
                        initializeEmittersPool(jetBeans, EModeLanguage.JAVA, monitor);
                        log.info("Initialize " + components.size() + " Templates in " //$NON-NLS-1$ //$NON-NLS-2$
                                + (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$
                        monitor.done();
                        DenguesUiPlugin.getDefault().getPreferenceStore().setValue(IDenguesPrefsConstant.REFRESH_JET_ALREADY,
                                true);
                    } catch (Exception e) {
                        log.error("Exception during Initialization", e); //$NON-NLS-1$
                    } finally {
                        initInProgress = false;
                    }
                    return Status.OK_STATUS;
                }

            };
            job.setUser(true);
            job.setPriority(Job.SHORT);
            job.schedule(); // start as soon as possible
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initializeEmittersPool".
     * 
     * @param jetBeans
     * @param java
     * @param monitor2
     */
    protected static void initializeEmittersPool(List<JETTemplateBean> jetBeans, EModeLanguage java, IProgressMonitor monitor2) {
        if (monitor2 == null) {
            monitor2 = new NullProgressMonitor();
        }
        IProgressMonitor sub = new SubProgressMonitor(monitor2, 1);
        emitterPool = new HashMap<JETTemplateBean, JETEmitter>();
        try {
            for (JETTemplateBean bean : jetBeans) {
                if (!emitterPool.containsKey(bean)) {
                    JETEmitter emitter = new JETEmitter(bean.getTemplateFullUri(), bean.getClassLoader());
                    HashMap<String, String> classPath = bean.getClassPath();
                    for (String key : classPath.keySet()) {
                        emitter.addVariable(key, classPath.get(key));
                    }
                    Boolean isRef = DenguesUiPlugin.getDefault().getPreferenceStore().getBoolean(
                            IDenguesPrefsConstant.REFRESH_JET_TEMP)
                            || !DenguesUiPlugin.getDefault().getPreferenceStore().getBoolean(
                                    IDenguesPrefsConstant.REFRESH_JET_ALREADY);
                    if (isRef) {
                        emitter.initialize(BasicMonitor.toMonitor(sub));
                    }
                    if (emitter.getMethod() != null) {
                        bean.setMethod(emitter.getMethod());
                        bean.setClassName(emitter.getMethod().getDeclaringClass().getName());
                    }
                    emitterPool.put(bean, emitter);
                    monitor2.worked(1);
                    PREC++;
                }
            }
        } catch (Exception e) {
            log.error("happen exception", e); //$NON-NLS-1$
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initComponent".
     * 
     * @param java
     * @param jetBeans
     * @param codePart
     * @param component
     */
    protected static void initComponent(EModeLanguage java, List<JETTemplateBean> jetBeans, EJETCodePart codePart,
            IXMLComponent component) {

        IComponentFilesNaming naming = new ComponentFilesNaming();
        String tempUri = component.getPathSource() + "/" + component.getName() + "/" //$NON-NLS-1$ //$NON-NLS-2$
                + naming.getJetFileName(component, java.getLanguageMode(), codePart);
        JETTemplateBean jetBean = new JETTemplateBean(component.getPluginId(), tempUri, component.getName(), component
                .getVersion(), java.getLanguageMode(), codePart.getName());
        jetBean.setClassLoader(new JETCodeGeneratorEmittersPoolFactory().getClass().getClassLoader());
        jetBeans.add(jetBean);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initializeUtilTemplate".
     * 
     * @param template
     * @param java
     * @return
     */
    protected static JETTemplateBean initializeUtilTemplate(JETTemplateUtil template, EModeLanguage java) {
        JETTemplateBean jetBean = new JETTemplateBean(DesignerCorePlugin.PLUGIN_ID,
                "resources" + "/" + template.getResourceName() //$NON-NLS-1$ //$NON-NLS-2$
                        + "." + java.getLanguageMode() + "jet", template.getResourceName(), template.getVersion(), java //$NON-NLS-1$ //$NON-NLS-2$
                        .getLanguageMode(), ""); //$NON-NLS-1$
        jetBean.setClassLoader(new JETCodeGeneratorEmittersPoolFactory().getClass().getClassLoader());
        return jetBean;
    }

    /**
     * Getter for emitterPool.
     * 
     * @return the emitterPool
     */
    public static HashMap<JETTemplateBean, JETEmitter> getEmitterPool() {
        return emitterPool;
    }
}
